﻿using DdddOcrLib;
using Microsoft.Playwright;
using Nett;
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using static GKScoreQueryHelper.FormMain;
using static Org.BouncyCastle.Math.EC.ECCurve;

namespace GKScoreQueryHelper
{


    public class CustomPage
    {
        public event ItemFinishedWorkHandler ItemFinished;
        public event SubTaskFinishedHandler SubTaskFinished;
        public event SubTaskStartedHandler SubTaskStarted;

        private int errorCount = 0;
        public bool Cancel { get; set; } = false;
        IPage Page { get; init; }
        string PageName { get; init; }
        string ExcelFile { get; init; }

        public DdddOcr Engine { get; init; }
        
        CustomConfiguration Config { get; init; }
        public CustomPage(IPage page, string pageName,DdddOcr engine, string excelFile, CustomConfiguration config)
        {
            Page = page;
            ExcelFile = excelFile;
            Config = config;
            PageName = pageName;
            Engine = engine;
        }

        public void CancleTask()
        {
            Cancel = true;
        }


        public async void RunAsync()
        {
        
            var templateFileName = ExcelFile;
            var dic = Utils.GetFields(templateFileName);
            //校验字段是否齐全
            string? errorString = Utils.ValideFields(Config.Format_fields, dic);
            if (errorString != null)
            {
                MessageBox.Show($"指定的Excel文件中未包含必需的字段：{errorString}", "未包含必需字段");
                return;
            }
            string bmh, sfzh;
            int itemCount = 0;
            var startTime = Environment.TickCount;
                using (FileStream fs = new FileStream(templateFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    var wb = WorkbookFactory.Create(fs);
                    var sh = wb.GetSheetAt(0);
                    itemCount = sh.PhysicalNumberOfRows - 1;

                    if (SubTaskStarted != null)
                    {
                        SubTaskStarted(PageName, itemCount);
                    }
                    Debug.WriteLine("线程启动...");

                    try
                    {
                        for (int i = 1; i < sh.PhysicalNumberOfRows; i++)
                        {
                            var row = sh.GetRow(i);
                            bmh = row.GetCell(dic["报名号"]).ToString();
                            sfzh = row.GetCell(dic["身份证号"]).ToString();



                            var score = await Query(this.Page, bmh, sfzh);
                            foreach (var kv in score)
                            {
                                row.CreateCell(dic[kv.Key]).SetCellValue(kv.Value);
                            }

                            Debug.WriteLine("完成一个项目...");


                            if (ItemFinished != null)
                            {
                                ItemFinished(PageName);
                            }


                            if (Cancel)
                            {
                                throw new Exception("用户取消");
                            }
                        }

                        using (FileStream fss = new FileStream($"{Config.Sp_work_folder}\\{PageName}_{Config.File_result}", FileMode.OpenOrCreate, FileAccess.Write))
                        {
                            wb.Write(fss);
                            wb.Close();
                        }

                        var endTime = Environment.TickCount;




                        if (SubTaskFinished != null)
                        {
                            SubTaskFinished(PageName, new SubTaskInformation { ItemCount = itemCount, ErrorCount = errorCount, TaskName = PageName, TaskDuration = TimeSpan.FromMilliseconds(endTime - startTime), });
                        }



                    }
                    catch(Exception ex) 
                    {
                    Debug.WriteLine(ex.Message);
                        using (FileStream fss = new FileStream($"{Config.Sp_work_folder}\\{PageName}_{Config.File_error}", FileMode.OpenOrCreate, FileAccess.Write))
                        {
                            wb.Write(fss);
                            wb.Close();
                        }

                    }

                }
               


 




        }

        public async Task<Dictionary<string, string>> Query(IPage page, string gkbmh, string sfzh)
        {

            await page.GotoAsync(Config.Server_URL);

            await TryValideCode(gkbmh, sfzh, 10);

            var table = page.Locator(Config.Page_cjtable);
            string[] t = new string[7];
            string[] s = new string[7];

            Dictionary<string, string> dic = new Dictionary<string, string>();


            for (int i = 0; i < 7; i++)
            {
                var tr = table.Locator("tr").Nth(i + 1);
                dic.Add(await tr.Locator("td").First.InnerTextAsync(), await tr.Locator("td").Nth(1).InnerTextAsync());
                //t[i] = tr.Locator("td").First.InnerTextAsync().Result;
                //s[i] = tr.Locator("td").Nth(1).InnerTextAsync().Result;
                //Debug.WriteLine($"学科:{t[i]},分数:{s[i]}");
            }

            return dic;
        }

        private async Task TryValideCode(string gkbmh, string sfzh, int maxTimes)
        {
            int times = 0;
            bool success = false;

            while (times < maxTimes && !success)
            {

                await Page.Locator(Config.Page_gkbmh).ClickAsync();
                await Page.Locator(Config.Page_gkbmh).FillAsync(gkbmh);

                await Page.Locator(Config.Page_sfzh).ClickAsync();
                await Page.Locator(Config.Page_sfzh).FillAsync(sfzh);



                var img = await Page.Locator(Config.Page_valicode).ScreenshotAsync();

                var valicode = Engine.Classification(img);
                times++;
                if (valicode.Length != 5)
                {
                    await Page.GetByRole(AriaRole.Img, new() { Name = Config.Page_retry }).ClickAsync();
                    img = await Page.Locator(Config.Page_valicode).ScreenshotAsync();
                    valicode = Engine.Classification(img);
                    times++;
                    //Debug.WriteLine("尝试一次，识别出的验证码位数不正确！");
                    errorCount++;
                }


                await Page.Locator(Config.Page_yzm).FillAsync(valicode);


                //点击查询并等待页面加载成功！
                await Page.RunAndWaitForResponseAsync(async () =>
                {
                    await Page.Locator(Config.Page_submit).ClickAsync();
                }, response => response.Status == 200);

                //系统提醒验证码错误！！！！
                if (!(await Page.IsVisibleAsync(Config.Page_cjtable)))
                {
                    await Page.GetByRole(AriaRole.Link, new() { Name = Config.Page_next }).ClickAsync();
                    times++;
                    //Debug.WriteLine("尝试一次，位数正确，但是识别码错误！");
                    errorCount++;
                    continue;
                }

                if (Config.Runtime_debug)
                {
                    using (FileStream fs = new FileStream($"{Config.Runtime_debug_folder}\\{valicode}.png", FileMode.Create, FileAccess.Write))
                    {
                        fs.Write(img, 0, img.Length);
                        fs.Close();
                    }
                }
                success = true;
            }




        }



    }
    public delegate void ItemFinishedWorkHandler(string subWorkName);
    public delegate void SubTaskFinishedHandler(string subWorkName,SubTaskInformation subTaskInformation);
    public delegate void SubTaskStartedHandler(string subWorkName,int ItemCount);
    public class CustomCancleException : Exception
    {
        public override string Message { get; } = "用户取消";
    }
    public class SubTaskInformation
    {
        public string TaskName { get; set; } = string.Empty;
        public TimeSpan TaskDuration { get; set; }

        public int ItemCount { get; set; }

        public int ErrorCount { get; set; }

    }
}
